#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>


#define BYTE_LEN   92
#define SPI_CPHA   0x01
#define    SPI_BUFFER_OTA            0x320    //!< OTA APPLICATION

 ////////////////////////////////////////////////////////////
 //! @name messagetypes
 //! Types for SPI messages. Can be combined for e.g. NORM | BEGIN | END
 //! @{
#define    SPI_MSGTYPE_NORM        ( 0 << 0)    //!< normal
#define    SPI_MSGTYPE_CRIT            ( 1 << 0)    //!< critical
#define    SPI_MSGTYPE_FAIL            ( 1 << 1)    //!< failure
#define    SPI_MSGTYPE_BGN             ( 1 << 2)    //!< begin
#define    SPI_MSGTYPE_END             ( 1 << 3)    //!< end
#define    SPI_MSGTYPE_BINA            ( 1 << 4)    //!< binary for slot A
#define    SPI_MSGTYPE_BINB            ( 1 << 5)    //!< binary for slot B

static void pabort(const char *s)
{
	if (errno != 0)
		perror(s);
	else
		printf("%s\n",s);
	abort();
}
static const char *device = "/dev/spidev0.0";
static uint8_t bits = 8;
static uint32_t speed = 1000000;
static uint32_t mode;
typedef struct {
	uint16_t  size;                    //!< size of the whole struct
	uint16_t  bufftype:12;            //!< type of the BUFFER, SPI_BUFFER_OTA
	uint16_t  hBus:4;

	uint32_t  time[2];                //!< timestamp of message

	uint32_t  tag[2];                    //!< a tag field for user e.g. object pointer

	uint8_t   res1;                    //!< reserved for user e.g. available data size
	uint8_t   crc8;                    //!< crc8 of message
	uint16_t  msgtype;                //!< type of message, bitfield, see SPI_MSGTYPE_...

	uint32_t  id;                        //!< identifier of message

	uint8_t   data8[64];            //!< data of message (byte based)

} OTASPIMsg_t;


char spi_frame_RX[BYTE_LEN] = {0};
/**	for test
* size:0x0000
* bufftype: SPI_BUFFER_OTA : 0x0320
*/
OTASPIMsg_t spi_frame_TX = {
	.size = 0x0000,
	.bufftype = SPI_BUFFER_OTA,
	.hBus = 0x0,
	.time = {0x00000000,0x00000000},
	.tag = {0x00000002,0x00000000},
	.res1 = 0,
	.crc8 = 0,
	.msgtype = (SPI_MSGTYPE_NORM | SPI_MSGTYPE_BGN | SPI_MSGTYPE_BINA),
	.id = 0x00000000,
	.data8 = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
			0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
			0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
			0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
			0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
			0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
			0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
			0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F}
};
/*
 执行硬件上的SPI数据传输 
 fd:SPI设备文件句柄
 tx:发送缓冲器指针
 rx:接收缓冲区指针
 len:收发的数据个数
*/
static int transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
	int ret = 0;
	struct spi_ioc_transfer tr;
	/* 设置SPI传输的控制结构体 */
	memset(&tr, 0, sizeof(struct spi_ioc_transfer));
	tr.tx_buf = (unsigned long)tx;	// 发送缓冲区
	tr.rx_buf = (unsigned long)rx;	// 接收缓冲区
	tr.len = len;					// 收发数据个数
	tr.delay_usecs = 0;				// SPI周期间的延时
	tr.speed_hz = speed;			// SPI时钟频率
	tr.bits_per_word = bits;		// SPI周期中的字节的bit数
	/* 执行SPI传输 */
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	usleep(3000);
	if (ret < 1)
	{
		printf("\ncan't send spi message\r\n");
		return (ret = 1);
	}
	return (ret = 0);
}


int main(int argc, char *argv[])
{
	int ret = 0;
	int fd;
	int k = 0;
	
	unsigned char rx[BYTE_LEN] = {0};
	unsigned char tx[BYTE_LEN] = {0};
	unsigned char spi_data_ok = 0;
	/* 打开SPI设备 */
	fd = open(device, O_RDWR);
	if (fd < 0)
	{
		printf("can't open device");
		return (ret = -1);
	}
	//set spi mode
	mode |= SPI_CPHA;
	ret = ioctl(fd,SPI_IOC_WR_MODE32,&mode);
	
	if(ret == -1)
		pabort("can't set spi mode");


	//发送SPI数据，并获得接收到的SPI数据
	memcpy(tx, (char *)&spi_frame_TX, BYTE_LEN);
	ret = transfer(fd, tx, rx, BYTE_LEN);

	memcpy((char *)&spi_frame_RX, rx, BYTE_LEN);

	for(unsigned int i=0; i<92; i++)
	{
		printf("%02x ", rx[i]);
	}

	close(fd);

	return ret;
}
